home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / vtrm / part02 < prev    next >
Encoding:
Internet Message Format  |  1987-02-11  |  40.2 KB

  1. Subject:  v08i060:  A Unix/PC virtual terminal package, Part02/02
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: Guido van Rossum <seismo!mcvax!guido>
  6. Mod.sources: Volume 8, Issue 60
  7. Archive-name: vtrm/Part02
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line,
  11. # then unpack it by saving it in a file and typing "sh file".
  12. # If all goes well, you will see the message "End of archive 2 (of 2)."
  13. # Contents:  vtrm.c
  14. PATH=/bin:/usr/bin:/usr/ucb; export PATH
  15. echo shar: extracting "'vtrm.c'" '(38157 characters)'
  16. if test -f 'vtrm.c' ; then 
  17.   echo shar: will not over-write existing file "'vtrm.c'"
  18. else
  19. sed 's/^X//' >vtrm.c <<'@//E*O*F vtrm.c//'
  20. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  21. X
  22. X#define lenline len_line /* Avoid name conflict with lenline in tex.c */
  23. X
  24. X/*
  25. X * Virtual TeRMinal package.
  26. X * (For a description see at the end of this file.)
  27. X *
  28. X * TO DO:
  29. X *    - add interrupt handling (trminterrupt)
  30. X *    - adapt to changed window size when suspended or at SIGWINCH
  31. X *      (unfortunately, the calling module must be changed first --
  32. X *      it is not prepared for the changed window size...)
  33. X */
  34. X
  35. X/*
  36. X * Includes and data definitions.
  37. X */
  38. X
  39. X#include <stdio.h>
  40. X#ifndef TERMIO
  41. X#include <sgtty.h>
  42. X#else
  43. X#include <termio.h>
  44. X#endif TERMIO
  45. X#include <signal.h>
  46. X#include <ctype.h>
  47. X
  48. X#include "trm.h"
  49. X
  50. Xchar *getenv();
  51. Xint tgetent();
  52. Xint tgetnum();
  53. Xint tgetflag();
  54. Xchar *tgetstr();
  55. X
  56. X#ifdef TRACE
  57. X#define Tprintf(args) fprintf args
  58. X#else
  59. X#define Tprintf(args) /*empty*/
  60. X#endif
  61. X
  62. X#ifdef lint
  63. X#define VOID (void)
  64. X#else
  65. X#define VOID
  66. X#endif
  67. X
  68. X#define Forward
  69. X#define Visible
  70. X#define Hidden static
  71. X#define Procedure
  72. X
  73. Xtypedef char *string;
  74. Xtypedef int bool;
  75. X#define Yes 1
  76. X#define No  0
  77. X
  78. X#define Min(a,b) ((a) <= (b) ? (a) : (b))
  79. X
  80. X/* tty modes */
  81. X#ifndef TERMIO
  82. X
  83. X/* v7/BSD tty control */
  84. XHidden struct sgttyb oldtty, newtty;
  85. X#ifdef TIOCSETN
  86. X/* Redefine stty to uses TIOCSETN, so type-ahead is not flushed */
  87. X#define stty(fd, bp) VOID ioctl(fd, (int) TIOCSETN, (char *) bp)
  88. X#endif
  89. X
  90. X#ifdef TIOCSLTC /* BSD -- local special chars, must all be turned off */
  91. Xstatic struct ltchars oldltchars;
  92. Xstatic struct ltchars newltchars= {-1, -1, -1, -1, -1, -1};
  93. X#endif TIOCSLTC
  94. X
  95. X#ifdef TIOCSETC /* V7 -- standard special chars, some must be turned off too */
  96. Xstatic struct tchars oldtchars;
  97. Xstatic struct tchars newtchars;
  98. X#endif TIOCSETC
  99. X
  100. X#else TERMIO
  101. X
  102. X/* AT&T tty control */
  103. XHidden struct termio oldtty, newtty;
  104. X#define gtty(fd,bp) ioctl(fd, TCGETA, (char *) bp)
  105. X#define stty(fd,bp) VOID ioctl(fd, TCSETAW, (char *) bp)
  106. X
  107. X#endif TERMIO
  108. X
  109. XHidden bool know_ttys = No;
  110. X
  111. X/* visible data for termcap */
  112. Xchar PC;
  113. Xchar *BC;
  114. Xchar *UP;
  115. Xshort ospeed;
  116. X
  117. XForward int outchar();         /* procedure for termcap's tputs */
  118. X#define Putstr(str)    tputs((str), 1, outchar)
  119. Xextern char *tgoto();
  120. X
  121. X/* termcap terminal capabilities */
  122. X
  123. XHidden int lines;
  124. XHidden int cols;
  125. X
  126. X/*
  127. X * String-valued capabilities are saved in one big array.
  128. X * Extend this only at the end (even though it disturbs the sorting)
  129. X * because otherwise you have to change all macros...
  130. X */
  131. X
  132. X#define par_al_str strcaps[0]    /* parametrized al (AL) */
  133. X#define cap_cm_str strcaps[1]    /* screen-relative cursor motion (CM) */
  134. X#define par_dl_str strcaps[2]    /* parametrized dl (DL) */
  135. X#define al_str strcaps[3]     /* add new blank line */
  136. X#define cd_str strcaps[4]     /* clear to end of display */
  137. X#define ce_str strcaps[5]     /* clear to end of line */
  138. X#define cl_str strcaps[6]     /* cursor home and clear screen */
  139. X#define cm_str strcaps[7]     /* cursor motion */
  140. X#define cp_str strcaps[8]    /* cursor position sense reply */
  141. X#define cr_str strcaps[9]     /* carriage return */
  142. X#define cs_str strcaps[10]     /* change scrolling region */
  143. X#define dc_str strcaps[11]     /* delete character */
  144. X#define dl_str strcaps[12]     /* delete line */
  145. X#define dm_str strcaps[13]     /* enter delete mode */
  146. X#define do_str strcaps[14]     /* cursor down one line */
  147. X#define ed_str strcaps[15]     /* end delete mode */
  148. X#define ei_str strcaps[16]     /* end insert mode */
  149. X#define ho_str strcaps[17]    /* cursor home */
  150. X#define ic_str strcaps[18]     /* insert character (if necessary; may pad) */
  151. X#define im_str strcaps[19]     /* enter insert mode */
  152. X#define nd_str strcaps[20]     /* cursor right (non-destructive space) */
  153. X#define nl_str strcaps[21]    /* newline */
  154. X#define se_str strcaps[22]     /* end standout mode */
  155. X#define sf_str strcaps[23]     /* scroll text up (from bottom of region) */
  156. X#define so_str strcaps[24]     /* begin standout mode */
  157. X#define sp_str strcaps[25]    /* sense cursor position */
  158. X#define sr_str strcaps[26]     /* scroll text down (from top of region) */
  159. X#define te_str strcaps[27]     /* end termcap */
  160. X#define ti_str strcaps[28]     /* start termcap */
  161. X#define vb_str strcaps[29]     /* visible bell */
  162. X#define ve_str strcaps[30]     /* make cursor visible again */
  163. X#define vi_str strcaps[31]     /* make cursor invisible */
  164. X#define le_str strcaps[32]     /* cursor left */
  165. X#define bc_str strcaps[33]    /* backspace character */
  166. X#define up_str strcaps[34]     /* cursor up */
  167. X#define pc_str strcaps[35]    /* pad character */
  168. X#define ks_str strcaps[36]    /* keypad mode start */
  169. X#define ke_str strcaps[37]    /* keypad mode end */
  170. X/* Insert new entries here only! Don't forget to change the next line! */
  171. X#define NSTRCAPS 38 /* One more than the last entry's index */
  172. X
  173. XHidden char *strcaps[NSTRCAPS];
  174. XHidden char strcapnames[] =
  175. X"ALCMDLalcdceclcmcpcrcsdcdldmdoedeihoicimndnlsesfsospsrtetivbvevilebcuppckske";
  176. X
  177. X/* Same for Boolean-valued capabilities */
  178. X
  179. X#define has_am flagcaps[0]    /* has automatic margins */
  180. X#define has_da flagcaps[1]    /* display may be retained above screen */
  181. X#define has_db flagcaps[2]    /* display may be retained below screen */
  182. X#define has_in flagcaps[3]    /* not save to have null chars on the screen */
  183. X#define has_mi flagcaps[4]    /* move safely in insert (and delete?) mode */
  184. X#define has_ms flagcaps[5]    /* move safely in standout mode */
  185. X#define has_xs flagcaps[6]    /* standout not erased by overwriting */
  186. X#define has_bs flagcaps[7]    /* terminal can backspace */
  187. X#define hardcopy flagcaps[8]    /* hardcopy terminal */
  188. X#define NFLAGS 9
  189. X
  190. XHidden char flagcaps[NFLAGS];
  191. XHidden char flagnames[]= "amdadbinmimsxsbshc";
  192. X
  193. XHidden Procedure
  194. Xgetcaps(parea)
  195. X    register char *parea;
  196. X{
  197. X    register char *capname;
  198. X    register char **capvar;
  199. X    register char *flagvar;
  200. X
  201. X    for (capname= flagnames, flagvar= flagcaps;
  202. X            *capname != '\0'; capname += 2, ++flagvar)
  203. X        *flagvar= tgetflag(capname);
  204. X
  205. X    for (capname= strcapnames, capvar= strcaps;
  206. X            *capname != '\0'; capname += 2, ++capvar)
  207. X        *capvar= tgetstr(capname, parea);
  208. X}
  209. X
  210. X/* terminal status */
  211. X
  212. X/* calling order of Visible Procs */
  213. XHidden bool started = No;
  214. X
  215. X/* to exports the capabilities mentioned in vtrm.h: */
  216. XHidden int flags = 0;
  217. X
  218. X/* cost for impossible operations */
  219. X#define Infinity 9999
  220. X    /* Allow for adding Infinity+Infinity within range */
  221. X    /* (Range is assumed at least 2**15 - 1) */
  222. X
  223. X/* The following for all sorts of undefined things (except for UNKNOWN char) */
  224. X#define Undefined (-1)
  225. X
  226. X/* current mode of putting char's */
  227. X#define Normal    0
  228. X#define Insert    1
  229. X#define    Delete    2
  230. XHidden short mode = Normal;
  231. X
  232. X/* current standout mode */
  233. X#define Off    0
  234. X#define On    0200
  235. XHidden short so_mode = Off;
  236. X
  237. X/* masks for char's and short's */
  238. X#define NULCHAR    '\000'
  239. X#define CHAR    0177
  240. X#define SOBIT    On
  241. X#define SOCHAR    0377
  242. X/* if (has_xs) record cookies placed on screen in extra bit */
  243. X/* type of cookie is determined by the SO bit */
  244. X#define XSBIT    0400
  245. X#define SOCOOK    0600
  246. X#define COOKBITS SOCOOK
  247. X#define UNKNOWN    1
  248. X#define NOCOOK    UNKNOWN
  249. X
  250. X/* current cursor position */
  251. XHidden short cur_y = Undefined, cur_x = Undefined;
  252. X
  253. X/* "line[y][x]" holds the char on the terminal, with the SOBIT and XSBIT.
  254. X * the SOBIT tells whether the character is standing out, the XSBIT whether
  255. X * there is a cookie on the screen at this position.
  256. X * In particular a standend-cookie may be recorded AFTER the line
  257. X * (just in case some trmputdata will write after that position).
  258. X * "lenline[y]" holds the length of the line.
  259. X * Unknown chars will be 1, so the optimising compare in putline will fail.
  260. X * (Partially) empty lines are distinghuished by "lenline[y] < cols".
  261. X */
  262. XHidden short **line = 0, *lenline = 0;
  263. X
  264. X/* Clear the screen initially iff only memory cursor addressing available */
  265. XHidden bool mustclear = No;
  266. X
  267. X/* Make the cursor invisible when trmsync() tries to move outside the screen */
  268. XHidden bool no_cursor = No;
  269. X
  270. X/* Optimise cursor motion */
  271. XHidden int abs_cost;         /* cost of absolute cursor motion */
  272. XHidden int cr_cost;         /* cost of carriage return */
  273. XHidden int do_cost;         /* cost of down */
  274. XHidden int le_cost;         /* cost of left */
  275. XHidden int nd_cost;         /* cost of right */
  276. XHidden int up_cost;         /* cost of up */
  277. X
  278. X/* Optimise trailing match in put_line, iff the terminal can insert and delete
  279. X * characters; the cost per n characters will be:
  280. X *     n * MultiplyFactor + OverHead
  281. X */
  282. XHidden int ins_mf, ins_oh, del_mf, del_oh;
  283. XHidden int ed_cost, ei_cost;         /* used in move() */
  284. X
  285. X/* The type of scrolling possible determines which routines get used;
  286. X * these may be:
  287. X * (1) with addline and deleteline (termcap: al_str & dl_str);
  288. X * (2) with a settable scrolling region, like VT100 (cs_str, sr_str, sf_str);
  289. X * (3) no scrolling available. (NOT YET IMPLEMENTED)
  290. X */
  291. XHidden Procedure (*scr_up)();
  292. XHidden Procedure (*scr_down)();
  293. XForward Procedure scr1up();
  294. XForward Procedure scr1down();
  295. XForward Procedure scr2up();
  296. XForward Procedure scr2down();
  297. X/*Forward Procedure scr3up(); */
  298. X/*Forward Procedure scr3down(); */
  299. X
  300. X/*
  301. X * Starting, Ending and (fatal) Error.
  302. X */
  303. X
  304. X/* 
  305. X * Initialization call.
  306. X * Determine terminal capabilities from termcap.
  307. X * Set up tty modes.
  308. X * Start up terminal and internal administration.
  309. X * Return 0 if all well, error code if in trouble.
  310. X */
  311. XVisible int
  312. Xtrmstart(plines, pcols, pflags)
  313. Xint *plines;
  314. Xint *pcols;
  315. Xint *pflags;
  316. X{
  317. X    register int err;
  318. X    
  319. X    Tprintf((stderr, "\ttrmstart(&li, &co, &fl);\n"));
  320. X    if (started)
  321. X        return TE_TWICE;
  322. X    err= gettermcaps();
  323. X    if (err != TE_OK)
  324. X        return err;
  325. X    err= setttymode();
  326. X    if (err != TE_OK)
  327. X        return err;
  328. X    err= start_trm();
  329. X    if (err != TE_OK) {
  330. X        trmend();
  331. X        return err;
  332. X    }
  333. X
  334. X    *plines = lines;
  335. X    *pcols = cols;
  336. X    *pflags = flags;
  337. X
  338. X    started = Yes;
  339. X    return TE_OK;
  340. X}
  341. X
  342. X/*
  343. X * Termination call.
  344. X * Reset tty modes, etc.
  345. X * Beware that it might be called by a caught interrupt even in the middle
  346. X * of trmstart()!
  347. X */
  348. XVisible Procedure
  349. Xtrmend()
  350. X{
  351. X    Tprintf((stderr, "\ttrmend();\n"));
  352. X    set_mode(Normal);
  353. X    if (so_mode != Off)
  354. X        standend();
  355. X    Putstr(ke_str);
  356. X    Putstr(te_str);
  357. X    VOID fflush(stdout);
  358. X    resetttymode();
  359. X
  360. X    started = No;
  361. X}
  362. X
  363. X/*
  364. X * Set all internal statuses to undefined, especially the contents of
  365. X * the screen, so a hard redraw will not be optimised to heaven.
  366. X */
  367. XVisible Procedure
  368. Xtrmundefined()
  369. X{
  370. X    register int y, x;
  371. X    Tprintf((stderr, "\ttrmundefined();\n"));
  372. X
  373. X    cur_y = cur_x = Undefined;
  374. X    mode = so_mode = Undefined;
  375. X    
  376. X    for (y = 0; y < lines; y++) {
  377. X        for (x = 0; x <= cols; x++)
  378. X            line[y][x] = 1; /* impossible char, no so bits */
  379. X        lenline[y] = cols;
  380. X    }
  381. X}
  382. X
  383. X#ifndef NDEBUG
  384. XHidden Procedure
  385. Xcheck_started(m)
  386. Xchar *m;
  387. X{
  388. X    if (!started) {
  389. X        trmend();
  390. X        fprintf(stderr, "bad VTRM call\n");
  391. X        abort();
  392. X    }
  393. X}
  394. X#else
  395. X#define check_started(m) /*empty*/
  396. X#endif
  397. X
  398. XHidden int ccc;
  399. X
  400. X/*ARGSUSED*/
  401. XHidden Procedure
  402. Xcountchar(ch)
  403. Xchar ch;
  404. X{
  405. X    ccc++;
  406. X}
  407. X
  408. XHidden int
  409. Xstrcost(str)
  410. Xchar *str;
  411. X{
  412. X    if (str == NULL)
  413. X        return Infinity;
  414. X    return str0cost(str);
  415. X}
  416. X
  417. XHidden int
  418. Xstr0cost(str)
  419. Xchar *str;
  420. X{
  421. X    ccc = 0;
  422. X    tputs(str, 1, countchar);
  423. X    return ccc;
  424. X}
  425. X
  426. X/*
  427. X * Get terminal capabilities from termcap and compute related static
  428. X * properties.  Return TE_OK if all well, error code otherwise.
  429. X *
  430. X * TO DO:
  431. X *    - use the curses trick of a reading the capabilities in a loop
  432. X *      rather than one at a time.
  433. X */
  434. X
  435. XHidden int
  436. Xgettermcaps() 
  437. X{
  438. X    string trmname;
  439. X    char tc_buf[1024];
  440. X    static char strbuf[1024];
  441. X    char *area = strbuf;
  442. X    int sg;
  443. X    static bool tc_initialized = No;
  444. X#ifdef TIOCGWINSZ
  445. X    struct winsize win;
  446. X#endif
  447. X
  448. X    if (tc_initialized)
  449. X        return TE_OK;
  450. X    
  451. X    trmname=getenv("TERM");
  452. X    if (trmname == NULL || trmname[0] == '\0')
  453. X        return TE_NOTERM;
  454. X    if (tgetent(tc_buf, trmname) != 1)
  455. X        return TE_BADTERM;
  456. X
  457. X    getcaps(&area); /* Read all flag and string type capabilities */
  458. X    if (hardcopy)
  459. X        return TE_DUMB;
  460. X    BC = le_str;
  461. X    if (BC == NULL) {
  462. X        BC = bc_str;
  463. X        if (BC == NULL) {
  464. X            if (has_bs)
  465. X                BC = "\b";
  466. X            else
  467. X                return TE_DUMB;
  468. X        }
  469. X    }
  470. X    UP = up_str;
  471. X    if (UP == NULL)
  472. X        return TE_DUMB;
  473. X    PC = (pc_str != NULL? pc_str[0] : NULCHAR);
  474. X
  475. X    if (cm_str == NULL) {
  476. X        cm_str = cap_cm_str;
  477. X        if (cm_str == NULL) {
  478. X            if (ho_str == NULL || do_str == NULL || nd_str == NULL)
  479. X                return TE_DUMB;
  480. X        }
  481. X        else
  482. X            mustclear = Yes;
  483. X    }
  484. X    if (al_str && dl_str) {
  485. X        scr_up = scr1up;
  486. X        scr_down = scr1down;
  487. X        flags |= CAN_SCROLL;
  488. X    }
  489. X    else {
  490. X        if (sf_str == NULL)
  491. X            sf_str = "\n";
  492. X        if (cs_str && sr_str) {
  493. X            scr_up = scr2up;
  494. X            scr_down = scr2down;
  495. X            flags |= CAN_SCROLL;
  496. X        }
  497. X        else
  498. X            return TE_DUMB;
  499. X    }
  500. X        
  501. X    lines = tgetnum("li");
  502. X    cols = tgetnum("co");
  503. X#ifdef TIOCGWINSZ
  504. X    if (ioctl(0, TIOCGWINSZ, &win) == 0) {
  505. X        if (win.ws_col > 0)
  506. X            cols = win.ws_col;
  507. X        if (win.ws_row > 0)
  508. X            lines = win.ws_row;
  509. X    }
  510. X#endif
  511. X    if (lines < 0) lines = 24;
  512. X    if (cols < 0) cols = 80;
  513. X    
  514. X    if ((sg=tgetnum("sg")) == 0)
  515. X        has_xs = Yes;
  516. X    else if (sg > 0)
  517. X        return TE_DUMB;
  518. X    
  519. X    if (!ce_str)
  520. X        return TE_DUMB;
  521. X    if (cr_str == NULL) cr_str = "\r";
  522. X    if (do_str == NULL) {
  523. X        do_str = nl_str;
  524. X        if (do_str == NULL) do_str = "\n";
  525. X    }
  526. X    le_str = BC;
  527. X    up_str = UP;
  528. X    if (vb_str == NULL)     /* then we will do with the audible bell */
  529. X        vb_str = "\007";
  530. X    
  531. X    /* cursor sensing (non standard) */
  532. X    if (cp_str != NULL && sp_str != NULL)
  533. X        flags |= CAN_SENSE;
  534. X
  535. X    if (so_str != NULL && se_str != NULL)
  536. X        flags |= HAS_STANDOUT;
  537. X
  538. X    /* calculate costs of local and absolute cursor motions */
  539. X    if (cm_str == NULL)
  540. X        abs_cost = Infinity;
  541. X    else
  542. X        abs_cost = strcost(tgoto(cm_str, 0, 0));
  543. X    cr_cost = strcost(cr_str);
  544. X    do_cost = strcost(do_str);
  545. X    le_cost = strcost(le_str);
  546. X    nd_cost = strcost(nd_str);
  547. X    up_cost = strcost(up_str);
  548. X
  549. X    /* cost of leaving insert or delete mode, used in move() */
  550. X    ei_cost = str0cost(ei_str);
  551. X    ed_cost = str0cost(ed_str);
  552. X    
  553. X    /* calculate insert and delete cost multiply_factor and overhead */
  554. X    if (((im_str && ei_str) || ic_str) && dc_str) {
  555. X        flags |= CAN_OPTIMISE;
  556. X        ins_mf = 1 + str0cost(ic_str);
  557. X        ins_oh = str0cost(im_str) + ei_cost;
  558. X        del_mf = str0cost(dc_str);
  559. X        del_oh = str0cost(dm_str) + ed_cost;
  560. X    }
  561. X        
  562. X    tc_initialized = Yes;
  563. X    return TE_OK;
  564. X}
  565. X
  566. XHidden int
  567. Xsetttymode()
  568. X{
  569. X    if (!know_ttys) {
  570. X        if (gtty(0, &oldtty) != 0 || gtty(0, &newtty) != 0)
  571. X            return TE_NOTTY;
  572. X#ifndef TERMIO
  573. X        ospeed = oldtty.sg_ospeed;
  574. X#ifdef PWB
  575. X        newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
  576. X                  | RAW;
  577. X#else PWB
  578. X        newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
  579. X                  | CBREAK;
  580. X#endif PWB
  581. X#ifdef TIOCSLTC
  582. X    VOID ioctl(0, (int) TIOCGLTC, (char *) &oldltchars);
  583. X#endif
  584. X#ifdef TIOCSETC
  585. X    VOID ioctl(0, (int) TIOCGETC, (char *) &oldtchars);
  586. X#endif
  587. X
  588. X#else TERMIO
  589. X        ospeed= oldtty.c_lflag & CBAUD;
  590. X        newtty.c_iflag &= ~ICRNL; /* No CR->NL mapping on input */
  591. X        newtty.c_oflag &= ~ONLCR; /* NL doesn't output CR */
  592. X        newtty.c_lflag &= ~(ICANON|ECHO); /* No line editing, no echo */
  593. X        newtty.c_cc[VMIN]= 3; /* wait for 3 characters */
  594. X        newtty.c_cc[VTIME]= 1; /* or 0.1 sec. */
  595. X#endif TERMIO
  596. X        know_ttys = Yes;
  597. X    }
  598. X    stty(0, &newtty);
  599. X#ifndef TERMIO
  600. X#ifdef TIOCSLTC
  601. X    VOID ioctl(0, (int) TIOCSLTC, (char *) &newltchars);
  602. X#endif TIOCSLTC
  603. X#ifdef TIOCSETC
  604. X    VOID ioctl(0, (int) TIOCGETC, (char *) &newtchars);
  605. X    newtchars.t_intrc= -1;
  606. X#ifndef DEBUG
  607. X    newtchars.t_quitc= -1;
  608. X#endif
  609. X    newtchars.t_eofc= -1;
  610. X    newtchars.t_brkc= -1;
  611. X    VOID ioctl(0, (int) TIOCSETC, (char *) &newtchars);
  612. X#endif TIOCSETC
  613. X#endif TERMIO
  614. X    return TE_OK;
  615. X}
  616. X
  617. XHidden Procedure
  618. Xresetttymode()
  619. X{
  620. X    if (know_ttys) {
  621. X        stty(0, &oldtty);
  622. X#ifndef TERMIO
  623. X#ifdef TIOCSLTC
  624. X        VOID ioctl(0, (int) TIOCSLTC, (char *) &oldltchars);
  625. X#endif TIOCSLTC
  626. X#ifdef TIOCSETC
  627. X        VOID ioctl(0, (int) TIOCSETC, (char *) &oldtchars);
  628. X#endif TIOCSETC
  629. X#endif TERMIO
  630. X        know_ttys= No;
  631. X    }
  632. X}
  633. X
  634. XHidden int
  635. Xstart_trm()
  636. X{
  637. X    register int y;
  638. X
  639. X    if (line == NULL) {
  640. X        if ((line = (short**) malloc(lines * sizeof(short*))) == NULL)
  641. X            return TE_NOMEM;
  642. X        for (y = 0; y < lines; y++) {
  643. X            if ((line[y] = (short*)
  644. X                malloc((cols+1) * sizeof(short))) == NULL)
  645. X                return TE_NOMEM;
  646. X        }
  647. X    }
  648. X    if (lenline == NULL) {
  649. X        if ((lenline = (short*) malloc(lines * sizeof(short))) == NULL)
  650. X            return TE_NOMEM;
  651. X    }
  652. X
  653. X    trmundefined();
  654. X
  655. X    Putstr(ti_str);
  656. X    Putstr(ks_str);
  657. X    if (cs_str)
  658. X        Putstr(tgoto(cs_str, lines-1, 0));
  659. X    if (mustclear)
  660. X        clear_lines(0, lines-1);
  661. X    return TE_OK;
  662. X}
  663. X
  664. X
  665. X/*
  666. X * Sensing and moving the cursor.
  667. X */
  668. X
  669. X/*
  670. X * Sense the current (y, x) cursor position, after a possible manual
  671. X * change by the user with local cursor motions.
  672. X * If the terminal cannot be asked for the current cursor position,
  673. X * or if the string returned by the terminal is garbled,
  674. X * the position is made Undefined.
  675. X */
  676. X
  677. XVisible Procedure
  678. Xtrmsense(py, px)
  679. X    int *py;
  680. X    int *px;
  681. X{
  682. X    bool getpos();
  683. X
  684. X    Tprintf((stderr, "\ttrmsense(&yy, &xx);\n"));
  685. X    check_started("trmsense");
  686. X
  687. X    *py = *px = Undefined;
  688. X    set_mode(Normal);
  689. X    if (so_mode != Off)
  690. X        standend();
  691. X    
  692. X    if (flags&CAN_SENSE && getpos(py, px)) {
  693. X        if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
  694. X            *py = *px = Undefined;
  695. X    }
  696. X    cur_y = Undefined;
  697. X    cur_x = Undefined;
  698. X}
  699. X
  700. XHidden bool
  701. Xgetpos(py, px)
  702. Xint *py, *px;
  703. X{
  704. X    char *format = cp_str;
  705. X    int fc;         /* current format character */
  706. X    int ic;         /* current input character */
  707. X    int num;
  708. X    int on_y = 1;
  709. X    bool incr_orig = No;
  710. X    int i, ni;
  711. X
  712. X    Putstr(sp_str);
  713. X    VOID fflush(stdout);
  714. X
  715. X    while (fc = *format++) {
  716. X        if (fc != '%') {
  717. X            if (trminput() != fc)
  718. X                return No;
  719. X        }
  720. X        else {
  721. X            switch (fc = *format++) {
  722. X            case '%':
  723. X                if (trminput() != '%')
  724. X                    return No;
  725. X                continue;
  726. X            case 'r':
  727. X                on_y = 1 - on_y;
  728. X                continue;
  729. X            case 'i':
  730. X                incr_orig = Yes;
  731. X                continue;
  732. X            case 'd':
  733. X                ic = trminput();
  734. X                if (!isdigit(ic))
  735. X                    return No;
  736. X                num = ic - '0';
  737. X                while (isdigit(ic=trminput()))
  738. X                    num = 10*num + ic - '0';
  739. X                trmpushback(ic);
  740. X                break;
  741. X            case '2':
  742. X            case '3':
  743. X                ni = fc - '0';
  744. X                    num = 0;
  745. X                for (i=0; i<ni; i++) {
  746. X                    ic = trminput();
  747. X                    if (isdigit(ic))
  748. X                        num = 10*num + ic - '0';
  749. X                    else
  750. X                        return No;
  751. X                }
  752. X                break;
  753. X            case '+':
  754. X                num = trminput() - *format++;
  755. X                break;
  756. X            case '-':
  757. X                num = trminput() + *format++;
  758. X                break;
  759. X            default:
  760. X                return No;
  761. X            }
  762. X            /* assign num to parameter */
  763. X            if (incr_orig)
  764. X                num--;
  765. X            if (on_y)
  766. X                *py = num;
  767. X            else
  768. X                *px = num;
  769. X            on_y = 1 - on_y;
  770. X        }
  771. X    }
  772. X
  773. X    return Yes;
  774. X}
  775. X        
  776. X/* 
  777. X * To move over characters by rewriting them, we have to check:
  778. X * (1) that the screen has been initialised on these positions;
  779. X * (2) we do not screw up characters
  780. X * when rewriting line[y] from x_from upto x_to
  781. X */
  782. XHidden bool
  783. Xrewrite_ok(y, xfrom, xto)
  784. Xint y, xfrom, xto;
  785. X{
  786. X    register short *plnyx, *plnyto;
  787. X    
  788. X    if (xto > lenline[y])
  789. X        return No;
  790. X
  791. X    plnyto = &line[y][xto];
  792. X    for (plnyx = &line[y][xfrom]; plnyx <= plnyto; plnyx++)
  793. X        if (*plnyx == UNKNOWN
  794. X            ||
  795. X            (!has_xs && (*plnyx & SOBIT) != so_mode)
  796. X           )
  797. X            return No;
  798. X    return Yes;
  799. X}
  800. X        
  801. X/*
  802. X * Move to position y,x on the screen
  803. X */
  804. X/* possible move types for y and x respectively: */
  805. X#define None    0
  806. X#define Down    1
  807. X#define Up    2
  808. X#define Right    1
  809. X#define ReWrite    2
  810. X#define Left    3
  811. X#define CrWrite    4
  812. X
  813. XHidden Procedure
  814. Xmove(y, x)
  815. Xint y, x;
  816. X{
  817. X    int dy, dx;
  818. X    int y_cost, x_cost, y_move, x_move;
  819. X    int mode_cost;
  820. X    int xi;
  821. X    
  822. X    if (cur_y == y && cur_x == x)
  823. X        return;
  824. X    
  825. X    if (!has_mi || mode == Undefined)
  826. X        set_mode(Normal);
  827. X    if (!has_xs && ((!has_ms && so_mode != Off) || so_mode == Undefined))
  828. X        standend();
  829. X    
  830. X    if (cur_y == Undefined || cur_x == Undefined)
  831. X        goto absmove;
  832. X    
  833. X    dy = y - cur_y;
  834. X    dx = x - cur_x;
  835. X
  836. X    if (dy > 0) {
  837. X        y_move = Down;
  838. X        y_cost = dy * do_cost;
  839. X    }
  840. X    else if (dy < 0) {
  841. X        y_move = Up;
  842. X        y_cost = -dy * up_cost;
  843. X    }
  844. X    else {
  845. X        y_move = None;
  846. X        y_cost = 0;
  847. X    }
  848. X    if (y_cost < abs_cost) {
  849. X        switch (mode) {
  850. X        case Normal:
  851. X            mode_cost = 0;
  852. X            break;
  853. X        case Insert:
  854. X            mode_cost = ei_cost;
  855. X            break;
  856. X        case Delete:
  857. X            mode_cost = ed_cost;
  858. X            break;
  859. X        }
  860. X        if (dx > 0) {
  861. X            x_cost = dx + mode_cost;
  862. X            if (dx*nd_cost < x_cost || !rewrite_ok(y, cur_x, x)) {
  863. X                x_cost = dx * nd_cost;
  864. X                x_move = Right;
  865. X            }
  866. X            else
  867. X                x_move = ReWrite;
  868. X        }
  869. X        else if (dx < 0) {
  870. X            x_cost = -dx * le_cost;
  871. X            x_move = Left;
  872. X        }
  873. X        else {
  874. X            x_cost = 0;
  875. X            x_move = None;
  876. X        }
  877. X        if (cr_cost + x + mode_cost < x_cost && rewrite_ok(y, 0, x)) {
  878. X            x_move = CrWrite;
  879. X            x_cost = cr_cost + x + mode_cost;
  880. X        }
  881. X    }
  882. X    else
  883. X        x_cost = abs_cost;
  884. X
  885. X    if (y_cost + x_cost < abs_cost) {
  886. X        switch (y_move) {
  887. X        case Down:
  888. X            while (dy-- > 0) Putstr(do_str);
  889. X            break;
  890. X        case Up:
  891. X            while (dy++ < 0) Putstr(up_str);
  892. X            break;
  893. X        }
  894. X        switch (x_move) {
  895. X        case Right:
  896. X            while (dx-- > 0) Putstr(nd_str);
  897. X            break;
  898. X        case Left:
  899. X            while (dx++ < 0) Putstr(le_str);
  900. X            break;
  901. X        case CrWrite:
  902. X            Putstr(cr_str);
  903. X            cur_x = 0;
  904. X            /* FALL THROUGH */
  905. X        case ReWrite:
  906. X            set_mode(Normal);
  907. X            for (xi = cur_x; xi < x; xi++)
  908. X                putchar(line[y][xi]);
  909. X            break;
  910. X        }
  911. X    }
  912. X    else
  913. X    {
  914. X    absmove:
  915. X        if (cm_str == NULL) {
  916. X            Putstr(ho_str);
  917. X            for (cur_y = 0; cur_y < y; ++cur_y)
  918. X                Putstr(do_str);
  919. X            /* Should try to use tabs here: */
  920. X            for (cur_x = 0; cur_x < x; ++cur_x)
  921. X                Putstr(nd_str);
  922. X        }
  923. X        else
  924. X            Putstr(tgoto(cm_str, x, y));
  925. X    }
  926. X    
  927. X    cur_y = y;
  928. X    cur_x = x;
  929. X}
  930. X
  931. X
  932. X/*
  933. X * Putting data on the screen.
  934. X */
  935. X
  936. X/*
  937. X * Fill screen area with given data.
  938. X * Characters with the SO-bit (0200) set are put in standout mode.
  939. X */
  940. XVisible Procedure
  941. Xtrmputdata(yfirst, ylast, indent, data)
  942. Xint yfirst;
  943. Xint ylast;
  944. Xregister int indent;
  945. Xregister string data;
  946. X{
  947. X    register int y;
  948. X    int x, len, lendata, space;
  949. X        
  950. X    Tprintf((stderr, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data));
  951. X    check_started("trmputdata");
  952. X    
  953. X    if (yfirst < 0)
  954. X        yfirst = 0;
  955. X    if (ylast >= lines)
  956. X        ylast = lines-1;
  957. X    space = cols*(ylast-yfirst+1) - indent;
  958. X    if (space <= 0)
  959. X        return;
  960. X    yfirst += indent/cols;
  961. X    indent %= cols;
  962. X    y= yfirst;
  963. X    if (!data)
  964. X        data= ""; /* Safety net */
  965. X    x = indent;
  966. X    lendata = strlen(data);
  967. X    if (ylast == lines-1 && lendata >= space)
  968. X        lendata = space - 1;
  969. X    len = Min(lendata, cols-x);
  970. X    while (y <= ylast) {
  971. X        put_line(y, x, data, len);
  972. X        y++;
  973. X        lendata -= len;
  974. X        if (lendata > 0) {
  975. X            x = 0;
  976. X            data += len;
  977. X            len = Min(lendata, cols);
  978. X        }
  979. X        else
  980. X            break;
  981. X    }
  982. X    if (y <= ylast)
  983. X        clear_lines(y, ylast);
  984. X}
  985. X
  986. X/* 
  987. X * We will first try to get the picture:
  988. X *
  989. X *                  op>>>>>>>>>>>op          oq<<<<<<<<<<<<<<<<<<<<<<<<oq
  990. X *                  ^            ^           ^                         ^
  991. X *           <xskip><-----m1----><----od-----><-----------m2----------->
  992. X *   OLD:   "You're in a maze of twisty little pieces of code, all alike"
  993. X *   NEW:          "in a maze of little twisting pieces of code, all alike"
  994. X *                  <-----m1----><-----nd------><-----------m2----------->
  995. X *                  ^            ^             ^                         ^
  996. X *                  np>>>>>>>>>>>np            nq<<<<<<<<<<<<<<<<<<<<<<<<nq
  997. X * where
  998. X *    op, oq, np, nq are pointers to start and end of Old and New data,
  999. X * and
  1000. X *    xskip = length of indent to be skipped,
  1001. X *    m1 = length of Matching part at start,
  1002. X *    od = length of Differing mid on screen,
  1003. X *    nd = length of Differing mid in data to be put,
  1004. X *    m2 = length of Matching trail.
  1005. X *
  1006. X * Then we will try to find a long blank-or-cleared piece in <nd+m2>:
  1007. X *
  1008. X *    <---m1---><---d1---><---nb---><---d2---><---m2--->
  1009. X *              ^         ^         ^        ^         ^
  1010. X *              np        bp        bq1      nq        nend
  1011. X * where
  1012. X *    bp, bq are pointers to start and AFTER end of blank piece,
  1013. X * and
  1014. X *    d1 = length of differing part before blank piece,
  1015. X *    nb = length of blank piece to be skipped,
  1016. X *    d2 = length of differing part after blank piece.
  1017. X * Remarks:
  1018. X *    d1 + nb + d2 == nd,
  1019. X * and
  1020. X *    d2 maybe less than 0.
  1021. X */
  1022. XHidden int
  1023. Xput_line(y, xskip, data, len)
  1024. Xint y, xskip;
  1025. Xstring data;
  1026. Xint len;
  1027. X{
  1028. X    register short *op, *oq;
  1029. X    register char *np, *nq, *nend;
  1030. X    char *bp, *bq1, *p, *q;
  1031. X    int m1, m2, od, nd, delta, dd, d1, nb, d2;
  1032. X    bool skipping;
  1033. X    int cost, o_cost;     /* normal and optimising cost */
  1034. X    
  1035. X    /* calculate the magic parameters */
  1036. X    op = &line[y][xskip];
  1037. X    oq = &line[y][lenline[y]-1];
  1038. X    np = data;
  1039. X    nq = nend = data + len - 1;
  1040. X    m1 = m2 = 0;
  1041. X    while ((*op&SOCHAR) == (((short)*np)&SOCHAR) && op <= oq && np <= nq)
  1042. X        op++, np++, m1++;
  1043. X    if (flags & CAN_OPTIMISE)
  1044. X        while ((*oq&SOCHAR) == (((short)*nq)&SOCHAR) && op <= oq && np <= nq)
  1045. X            oq--, nq--, m2++;
  1046. X    od = oq - op + 1;
  1047. X    nd = nq - np + 1;
  1048. X    /* now we have the first picture above */
  1049. X
  1050. X    if (od==0 && nd==0)
  1051. X        return;
  1052. X    delta = nd - od;
  1053. X
  1054. X    /* find the blank piece */
  1055. X    p = q = bp = bq1 = np;
  1056. X    oq += m2;         /* back to current eol */
  1057. X    if (!has_in) {
  1058. X        while (p <= nend) {
  1059. X            while (q<=nend && *q==' ' && (op>oq || *op==' '))
  1060. X                q++, op++;
  1061. X            if (q - p > bq1 - bp)
  1062. X                bp = p, bq1 = q;
  1063. X            p = ++q;
  1064. X            op++;
  1065. X        }
  1066. X    }
  1067. X    d1 = bp - np;
  1068. X    nb = bq1 - bp;
  1069. X    d2 = nq - bq1 + 1;
  1070. X    
  1071. X    /* what is cheapest:
  1072. X     *    normal: put nd+m2;                         (dd = nd+m2)
  1073. X     *    skipping: put d1, skip nb, put d2+m2;      (dd = d2+m2)
  1074. X     *    optimise: put dd, insert or delete delta.  (dd = min(od,nd))
  1075. X     */
  1076. X    cost = nd + m2;     /* normal cost */
  1077. X    if (nb > abs_cost || (d1 == 0 && nb > 0)) {
  1078. X        skipping = Yes;
  1079. X        cost -= nb - (d1>0 ? abs_cost : 0); /* skipping cost */
  1080. X        dd = d2;
  1081. X    }
  1082. X    else {
  1083. X        skipping = No;
  1084. X        dd = nd;
  1085. X    }
  1086. X    
  1087. X    if (m2 != 0) {
  1088. X        /* try optimising */
  1089. X        o_cost = Min(od, nd);
  1090. X        if (delta > 0)
  1091. X            o_cost += delta * ins_mf + ins_oh;
  1092. X        else if (delta < 0)
  1093. X            o_cost += -delta * del_mf + del_oh;
  1094. X        if (o_cost >= cost) {
  1095. X            /* discard m2, no optimise */
  1096. X            dd += m2;
  1097. X            m2 = 0;
  1098. X        }
  1099. X        else {
  1100. X            dd = Min(od, nd);
  1101. X            skipping = No;
  1102. X        }
  1103. X    }
  1104. X
  1105. X    /* and now for the real work */
  1106. X    if (!skipping || d1 > 0)
  1107. X        move(y, xskip + m1);
  1108. X
  1109. X    if (has_xs)
  1110. X        get_so_mode();
  1111. X    
  1112. X    if (skipping) {
  1113. X        if (d1 > 0) {
  1114. X            set_mode(Normal);
  1115. X            put_str(np, d1, No);
  1116. X        }
  1117. X        if (has_xs && so_mode != Off)
  1118. X            standend();
  1119. X        set_blanks(y, xskip+m1+d1, xskip+m1+d1+nb);
  1120. X        if (dd != 0 || delta < 0) {
  1121. X            move(y, xskip+m1+d1+nb);
  1122. X            np = bq1;
  1123. X        }
  1124. X    }
  1125. X    
  1126. X    if (dd > 0) {
  1127. X        set_mode(Normal);
  1128. X        put_str(np, dd, No);
  1129. X    }
  1130. X    
  1131. X    if (m2 > 0) {
  1132. X        if (delta > 0) {
  1133. X            set_mode(Insert);
  1134. X            ins_str(np+dd, delta);
  1135. X        }
  1136. X        else if (delta < 0) {
  1137. X            if (so_mode != Off)
  1138. X                standend();
  1139. X                /* Some terminals fill with standout spaces! */
  1140. X            set_mode(Delete);
  1141. X            del_str(-delta);
  1142. X        }
  1143. X    }
  1144. X    else {
  1145. X        if (delta < 0) {
  1146. X            clr_to_eol();
  1147. X            return;
  1148. X        }
  1149. X    }
  1150. X    
  1151. X    lenline[y] = xskip + len;
  1152. X    if (cur_x == cols) {
  1153. X        if (!has_mi)
  1154. X            set_mode(Normal);
  1155. X        if (!has_ms)
  1156. X            so_mode = Undefined;
  1157. X        if (has_am)
  1158. X            cur_y++;
  1159. X        else
  1160. X            Putstr(cr_str);
  1161. X        cur_x = 0;
  1162. X    }
  1163. X    else if (has_xs) {
  1164. X        if (m2 == 0) {
  1165. X            if (so_mode == On)
  1166. X                standend();
  1167. X        }
  1168. X        else {
  1169. X            if (!(line[cur_y][cur_x] & XSBIT)) {
  1170. X                if (so_mode != (line[cur_y][cur_x] & SOBIT))
  1171. X                    (so_mode ? standend() : standout());
  1172. X            }
  1173. X        }
  1174. X    }
  1175. X}
  1176. X
  1177. XHidden Procedure
  1178. Xset_mode(m)
  1179. Xint m;
  1180. X{
  1181. X    if (m == mode)
  1182. X        return;
  1183. X    switch (mode) {
  1184. X    case Insert:
  1185. X        Putstr(ei_str);
  1186. X        break;
  1187. X    case Delete:
  1188. X        Putstr(ed_str);
  1189. X        break;
  1190. X    case Undefined:
  1191. X        Putstr(ei_str);
  1192. X        Putstr(ed_str);
  1193. X        break;
  1194. X    }
  1195. X    switch (m) {
  1196. X    case Insert:
  1197. X        Putstr(im_str);
  1198. X        break;
  1199. X    case Delete:
  1200. X        Putstr(dm_str);
  1201. X        break;
  1202. X    }
  1203. X    mode = m;
  1204. X}
  1205. X
  1206. XHidden Procedure
  1207. Xget_so_mode()
  1208. X{
  1209. X    if (cur_x >= lenline[cur_y] || line[cur_y][cur_x] == UNKNOWN)
  1210. X        so_mode = Off;
  1211. X    else
  1212. X        so_mode = line[cur_y][cur_x] & SOBIT;
  1213. X}
  1214. X
  1215. XHidden Procedure
  1216. Xstandout()
  1217. X{
  1218. X    Putstr(so_str);
  1219. X    so_mode = On;
  1220. X    if (has_xs)
  1221. X        line[cur_y][cur_x] |= SOCOOK;
  1222. X}
  1223. X
  1224. XHidden Procedure
  1225. Xstandend()
  1226. X{
  1227. X    Putstr(se_str);
  1228. X    so_mode = Off;
  1229. X    if (has_xs)
  1230. X        line[cur_y][cur_x] = (line[cur_y][cur_x] & ~SOBIT) | XSBIT;
  1231. X}
  1232. X
  1233. XHidden Procedure
  1234. Xput_str(data, n, inserting)
  1235. Xchar *data;
  1236. Xint n;
  1237. Xbool inserting;
  1238. X{
  1239. X    register short c, so;
  1240. X    short *ln_y_x, *ln_y_end;
  1241. X    
  1242. X    so = so_mode;
  1243. X    if (has_xs) {
  1244. X        ln_y_x = &line[cur_y][cur_x];
  1245. X        ln_y_end = &line[cur_y][lenline[cur_y]];
  1246. X    }
  1247. X    while (n-- > 0) {
  1248. X        if (has_xs && ln_y_x <= ln_y_end && ((*ln_y_x)&XSBIT))
  1249. X            so = so_mode = (*ln_y_x)&SOBIT;
  1250. X            /* this also checks for the standend cookie AFTER */
  1251. X            /* the line because off the equals sign in <= */
  1252. X        c = ((short)(*data++))&SOCHAR;
  1253. X        if ((c&SOBIT) != so) {
  1254. X            so = c&SOBIT;
  1255. X            so ? standout() : standend();
  1256. X         }
  1257. X        if (inserting)
  1258. X            Putstr(ic_str);
  1259. X        put_c(c);
  1260. X        if (has_xs)
  1261. X            ln_y_x++;
  1262. X    }
  1263. X}
  1264. X
  1265. XHidden Procedure
  1266. Xins_str(data, n)
  1267. Xchar *data;
  1268. Xint n;
  1269. X{
  1270. X    int x;
  1271. X    
  1272. X    /* x will start AFTER the line, because there might be a cookie */
  1273. X    for (x = lenline[cur_y]; x >= cur_x; x--)
  1274. X        line[cur_y][x+n] = line[cur_y][x];
  1275. X    put_str(data, n, Yes);
  1276. X}
  1277. X
  1278. XHidden Procedure
  1279. Xdel_str(n)
  1280. Xint n;
  1281. X{
  1282. X    int x, xto;
  1283. X    
  1284. X    xto = lenline[cur_y] - n; /* again one too far because of cookie */
  1285. X    if (has_xs) {
  1286. X        for (x = cur_x + n; x >= cur_x; x--) {
  1287. X            if (line[cur_y][x] & XSBIT)
  1288. X                break;
  1289. X        }
  1290. X        if (x >= cur_x)
  1291. X            line[cur_y][cur_x+n] =
  1292. X                (line[cur_y][cur_x+n] & CHAR)
  1293. X                |
  1294. X                (line[cur_y][x] & COOKBITS);
  1295. X    }
  1296. X    for (x = cur_x; x <= xto; x++)
  1297. X        line[cur_y][x] = line[cur_y][x+n];
  1298. X    while (n-- > 0)
  1299. X        Putstr(dc_str);
  1300. X}
  1301. X
  1302. XHidden Procedure
  1303. Xput_c(c)
  1304. Xint c;
  1305. X{
  1306. X    char ch;
  1307. X    short xs_flag;
  1308. X    
  1309. X    ch = c&CHAR;
  1310. X    if (!isprint(ch) && ch != ' ') /* V7 isprint doesn't include blank */
  1311. X        ch= '?';
  1312. X    putchar(ch);
  1313. X    if (has_xs)
  1314. X        xs_flag = line[cur_y][cur_x]&XSBIT;
  1315. X    else
  1316. X        xs_flag = 0;
  1317. X    line[cur_y][cur_x] = (c&SOCHAR)|xs_flag;
  1318. X    cur_x++;
  1319. X}
  1320. X
  1321. XHidden Procedure
  1322. Xclear_lines(yfirst, ylast)
  1323. Xint yfirst, ylast ;
  1324. X{
  1325. X    register int y;
  1326. X    
  1327. X    if (!has_xs && so_mode != Off)
  1328. X        standend();
  1329. X    if (cl_str && yfirst == 0 && ylast == lines-1) {
  1330. X        Putstr(cl_str);
  1331. X        cur_y = cur_x = 0;
  1332. X        for (y = 0; y < lines; ++y) {
  1333. X            lenline[y] = 0;
  1334. X            if (has_xs) line[y][0] = NOCOOK;
  1335. X        }
  1336. X        return;
  1337. X    }
  1338. X    for (y = yfirst; y <= ylast; y++) {
  1339. X        if (lenline[y] > 0) {
  1340. X            move(y, 0);
  1341. X            if (ylast == lines-1 && cd_str) {
  1342. X                Putstr(cd_str);
  1343. X                while (y <= ylast) {
  1344. X                    if (has_xs) line[y][0] = NOCOOK;
  1345. X                    lenline[y++] = 0;
  1346. X                }
  1347. X                break;
  1348. X            }
  1349. X            else {
  1350. X                clr_to_eol();
  1351. X            }
  1352. X        }
  1353. X    }
  1354. X}
  1355. X
  1356. XHidden Procedure
  1357. Xclr_to_eol()
  1358. X{
  1359. X    lenline[cur_y] = cur_x;
  1360. X    if (!has_xs && so_mode != Off)
  1361. X        standend();
  1362. X    Putstr(ce_str);
  1363. X    if (has_xs) {
  1364. X        if (cur_x == 0)
  1365. X            line[cur_y][0] = NOCOOK;
  1366. X        else if (line[cur_y][cur_x-1]&SOBIT)
  1367. X            standend();
  1368. X    }
  1369. X}
  1370. X
  1371. XHidden Procedure
  1372. Xset_blanks
  1373. X(y, xfrom, xto)
  1374. Xint y, xfrom, xto;
  1375. X{
  1376. X    register int x;
  1377. X    
  1378. X    for (x = xfrom; x < xto; x++) {
  1379. X        line[y][x] = (line[y][x]&XSBIT) | ' ';
  1380. X    }
  1381. X}
  1382. X
  1383. X/* 
  1384. X * outchar() is used by termcap's tputs;
  1385. X * we can't use putchar because that's probably a macro
  1386. X */
  1387. XHidden int
  1388. Xoutchar(ch)
  1389. Xchar ch;
  1390. X{
  1391. X    putchar(ch);
  1392. X}
  1393. X
  1394. X/*
  1395. X * Scrolling (part of) the screen up (or down, dy<0).
  1396. X */
  1397. X
  1398. XVisible Procedure
  1399. Xtrmscrollup(yfirst, ylast, by)
  1400. Xregister int yfirst;
  1401. Xregister int ylast;
  1402. Xregister int by;
  1403. X{
  1404. X    Tprintf((stderr, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by));
  1405. X    check_started("trmscrollup");
  1406. X    
  1407. X    if (yfirst < 0)
  1408. X        yfirst = 0;
  1409. X    if (ylast >= lines)
  1410. X        ylast = lines-1;
  1411. X
  1412. X    if (yfirst > ylast)
  1413. X        return;
  1414. X
  1415. X    if (!has_xs && so_mode != Off)
  1416. X        standend();
  1417. X    
  1418. X    if (by > 0 && yfirst + by > ylast
  1419. X        ||
  1420. X        by < 0 && yfirst - by > ylast)
  1421. X    {
  1422. X        clear_lines(yfirst, ylast);
  1423. X        return;
  1424. X    }
  1425. X    
  1426. X    if (by > 0) {
  1427. X        (*scr_up)(yfirst, ylast, by);
  1428. X        scr_lines(yfirst, ylast, by, 1);
  1429. X    }
  1430. X    else if (by < 0) {
  1431. X        (*scr_down)(yfirst, ylast, -by);
  1432. X        scr_lines(ylast, yfirst, -by, -1);
  1433. X    }
  1434. X}
  1435. X
  1436. XHidden Procedure
  1437. Xscr_lines(yfrom, yto, n, dy)
  1438. Xint yfrom, yto, n, dy;
  1439. X{
  1440. X    register int y;
  1441. X    short *saveln;
  1442. X    
  1443. X    while (n-- > 0) {
  1444. X        saveln = line[yfrom];
  1445. X        for (y = yfrom; y != yto; y += dy) {
  1446. X            line[y] = line[y+dy];
  1447. X            lenline[y] = lenline[y+dy];
  1448. X        }
  1449. X        line[yto] = saveln;
  1450. X        lenline[yto] = 0;
  1451. X        if (has_xs) line[yto][0] = NOCOOK;
  1452. X    }
  1453. X}
  1454. X
  1455. XHidden Procedure
  1456. Xscr1up(yfirst, ylast, n)
  1457. X    int yfirst;
  1458. X    int ylast;
  1459. X    int n;
  1460. X{
  1461. X    move(yfirst, 0);
  1462. X    dellines(n);
  1463. X    if (ylast < lines-1) {
  1464. X        move(ylast-n+1, 0);
  1465. X        addlines(n);
  1466. X    }
  1467. X}
  1468. X
  1469. X
  1470. XHidden Procedure
  1471. Xscr1down(yfirst, ylast, n)
  1472. X    int yfirst;
  1473. X    int ylast;
  1474. X    int n;
  1475. X{
  1476. X    if (ylast == lines-1) {
  1477. X        clear_lines(ylast-n+1, ylast);
  1478. X    }
  1479. X    else {
  1480. X        move(ylast-n+1, 0);
  1481. X        dellines(n);
  1482. X    }
  1483. X    move(yfirst, 0);
  1484. X    addlines(n);
  1485. X}
  1486. X
  1487. X
  1488. XHidden Procedure
  1489. Xaddlines(n)
  1490. Xregister int n;
  1491. X{
  1492. X    if (par_al_str && n > 1)
  1493. X            Putstr(tgoto(par_al_str, n, n));
  1494. X    else {
  1495. X        while (n-- > 0)
  1496. X            Putstr(al_str);
  1497. X    }
  1498. X}
  1499. X
  1500. X
  1501. XHidden Procedure
  1502. Xdellines(n)
  1503. Xregister int n;
  1504. X{
  1505. X    if (par_dl_str && n > 1)
  1506. X        Putstr(tgoto(par_dl_str, n, n));
  1507. X    else {
  1508. X        while (n-- > 0)
  1509. X            Putstr(dl_str);
  1510. X    }
  1511. X}
  1512. X
  1513. X
  1514. XHidden Procedure
  1515. Xscr2up(yfirst, ylast, n)
  1516. Xint yfirst, ylast, n;
  1517. X{
  1518. X    Putstr(tgoto(cs_str, ylast, yfirst));
  1519. X    cur_y = cur_x = Undefined;
  1520. X    move(ylast, 0);
  1521. X    while (n-- > 0) {
  1522. X        Putstr(sf_str);
  1523. X        if (has_db && ylast == lines-1)
  1524. X            clr_to_eol();
  1525. X    }
  1526. X    Putstr(tgoto(cs_str, lines-1, 0));
  1527. X    cur_y = cur_x = Undefined;
  1528. X}
  1529. X
  1530. X
  1531. XHidden Procedure
  1532. Xscr2down(yfirst, ylast, n)
  1533. Xint yfirst, ylast, n;
  1534. X{
  1535. X    Putstr(tgoto(cs_str, ylast, yfirst));
  1536. X    cur_y = cur_x = Undefined;
  1537. X    move(yfirst, 0);
  1538. X    while (n-- > 0) {
  1539. X        Putstr(sr_str);
  1540. X        if (has_da && yfirst == 0)
  1541. X            clr_to_eol();
  1542. X    }
  1543. X    Putstr(tgoto(cs_str, lines-1, 0));
  1544. X    cur_y = cur_x = Undefined;
  1545. X}
  1546. X
  1547. X
  1548. X/*
  1549. X * Synchronization, move cursor to given position (or previous if < 0).
  1550. X */
  1551. X
  1552. XVisible Procedure
  1553. Xtrmsync(y, x)
  1554. X    int y;
  1555. X    int x;
  1556. X{
  1557. X    Tprintf((stderr, "\ttrmsync(%d, %d);\n", y, x));
  1558. X    check_started("trmsync");
  1559. X    
  1560. X    if (0 <= y && y < lines && 0 <= x && x < cols) {
  1561. X        move(y, x);
  1562. X        if (no_cursor) {
  1563. X            Putstr(ve_str);
  1564. X            no_cursor = No;
  1565. X        }
  1566. X    }
  1567. X    else if (no_cursor == No) {
  1568. X        Putstr(vi_str);
  1569. X        no_cursor = Yes;
  1570. X    }
  1571. X    VOID fflush(stdout);
  1572. X}
  1573. X
  1574. X
  1575. X/*
  1576. X * Send a bell, visible if possible.
  1577. X */
  1578. X
  1579. XVisible Procedure
  1580. Xtrmbell()
  1581. X{
  1582. X    Tprintf((stderr, "\ttrmbell();\n"));
  1583. X    check_started("trmbell");
  1584. X    
  1585. X    Putstr(vb_str);
  1586. X    VOID fflush(stdout);
  1587. X}
  1588. X
  1589. X
  1590. X#ifdef SHOW
  1591. X
  1592. X/*
  1593. X * Show the current internal statuses of the screen on stderr.
  1594. X * For debugging only.
  1595. X */
  1596. X
  1597. XVisible Procedure
  1598. Xtrmshow(s)
  1599. Xchar *s;
  1600. X{
  1601. X    int y, x;
  1602. X    
  1603. X    fprintf(stderr, "<<< %s >>>\n", s);
  1604. X    for (y = 0; y < lines; y++) {
  1605. X        for (x = 0; x <= lenline[y] /*** && x < cols-1 ***/ ; x++) {
  1606. X            fputc(line[y][x]&CHAR, stderr);
  1607. X        }
  1608. X        fputc('\n', stderr);
  1609. X        for (x = 0; x <= lenline[y] && x < cols-1; x++) {
  1610. X            if (line[y][x]&SOBIT)
  1611. X                fputc('-', stderr);
  1612. X            else
  1613. X                fputc(' ', stderr);
  1614. X        }
  1615. X        fputc('\n', stderr);
  1616. X        for (x = 0; x <= lenline[y] && x < cols-1; x++) {
  1617. X            if (line[y][x]&XSBIT)
  1618. X                fputc('+', stderr);
  1619. X            else
  1620. X                fputc(' ', stderr);
  1621. X        }
  1622. X        fputc('\n', stderr);
  1623. X    }
  1624. X    fprintf(stderr, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
  1625. X    VOID fflush(stderr);
  1626. X}
  1627. X#endif
  1628. X
  1629. X
  1630. X/*
  1631. X * Return the next input character, or -1 if read fails.
  1632. X * Only the low 7 bits are returned, so reading in RAW mode is permissible
  1633. X * (although CBREAK is preferred if implemented).
  1634. X * To avoid having to peek in the input buffer for trmavail, we use the
  1635. X * 'read' system call rather than getchar().
  1636. X * (The interface allows 8-bit characters to be returned, to accomodate
  1637. X * larger character sets!)
  1638. X */
  1639. X
  1640. XHidden int pushback= -1;
  1641. X
  1642. Xint
  1643. Xtrminput()
  1644. X{
  1645. X    char c;
  1646. X
  1647. X    if (pushback >= 0) {
  1648. X        c= pushback;
  1649. X        pushback= -1;
  1650. X        return c;
  1651. X    }
  1652. X    if (read(0, &c, 1) <= 0)
  1653. X        return -1;
  1654. X    return c & 0177;
  1655. X}
  1656. X
  1657. Xtrmpushback(c)
  1658. X    int c;
  1659. X{
  1660. X    pushback= c;
  1661. X}
  1662. X
  1663. X
  1664. X/*
  1665. X * See if there's input available from the keyboard.
  1666. X * The code to do this is dependent on the type of Unix you have
  1667. X * (BSD, System V, ...).
  1668. X * Return value: 0 -- no input; 1 -- input; -1 -- unimplementable.
  1669. X * Note that each implementation form should first check pushback.
  1670. X *
  1671. X * TO DO:
  1672. X *    - Implement it for other than 4.x BSD! (notably System 5)
  1673. X */
  1674. X
  1675. X#ifdef SELECT
  1676. X
  1677. X#include <sys/time.h>
  1678. X
  1679. Xint
  1680. Xtrmavail()
  1681. X{
  1682. X    int nfound, nfds, readfds;
  1683. X    static struct timeval timeout= {0, 0};
  1684. X
  1685. X    if (pushback >= 0)
  1686. X        return 1;
  1687. X    readfds= 1 << 0;
  1688. X    nfds= 0+1;
  1689. X    nfound= select(nfds, &readfds, (int*) NIL, (int*) NIL, &timeout);
  1690. X    return nfound > 0;
  1691. X}
  1692. X
  1693. X#define TRMAVAIL_DEFINED
  1694. X
  1695. X#endif SELECT
  1696. X
  1697. X#if !defined(TRMAVAIL_DEFINED) && defined(FIONREAD)
  1698. X
  1699. Xint
  1700. Xtrmavail()
  1701. X{
  1702. X    long n;
  1703. X
  1704. X    if (pushback >= 0)
  1705. X        return 1;
  1706. X    ioctl(0, (int) FIONREAD, (char *) &n);
  1707. X    return n > 0;
  1708. X}
  1709. X
  1710. X#define TRMAVAIL_DEFINED
  1711. X
  1712. X#endif FIONREAD
  1713. X
  1714. X#ifndef TRMAVAIL_DEFINED
  1715. X
  1716. Xint
  1717. Xtrmavail()
  1718. X{
  1719. X    if (pushback >= 0)
  1720. X        return 1;
  1721. X    return -1;
  1722. X}
  1723. X
  1724. X#endif
  1725. X
  1726. X
  1727. X/*
  1728. X * Suspend the editor.
  1729. X * Should be called only after trmend and before trmstart!
  1730. X */
  1731. X
  1732. Xtrmsuspend()
  1733. X{
  1734. X    int (*oldsig)();
  1735. X    
  1736. X    oldsig= signal(SIGTSTP, SIG_IGN);
  1737. X    if (oldsig == SIG_IGN)
  1738. X        return; /* Could spawn a subshell here... */
  1739. X    trmend(); /* Safety net */
  1740. X    signal(SIGTSTP, oldsig);
  1741. X    kill(0, SIGSTOP);
  1742. X}
  1743. X
  1744. X
  1745. X/*
  1746. X * DESCRIPTION.
  1747. X *
  1748. X * This package uses termcap to determine the terminal capabilities.
  1749. X *
  1750. X * The lines and columns of our virtual terminal are numbered 
  1751. X *    y = {0...lines-1} from top to bottom, and
  1752. X *    x = {0...cols-1} from left to right,
  1753. X * respectively.
  1754. X *
  1755. X * The Visible Procedures in this package are:
  1756. X *
  1757. X * trmstart(&lines, &cols, &flags)
  1758. X *     Obligatory initialization call (sets tty modes etc.),
  1759. X *     Returns the height and width of the screen to the integers
  1760. X *     whose addresses are passed as parameters, and a flag that
  1761. X *    describes some capabilities.
  1762. X *    Function return value: 0 if all went well, an error code if there
  1763. X *    is any trouble.  No messages are printed for errors.
  1764. X *
  1765. X * trmundefined()
  1766. X *    Sets internal representation of screen and attributes to undefined.
  1767. X *    This is necessary for a hard redraw, which would get optimised to
  1768. X *    oblivion,
  1769. X *
  1770. X * trmsense(&y, &x)
  1771. X *    Returns the cursor position through its parameters
  1772. X *    after a possible manual change by the user.
  1773. X *
  1774. X * trmputdata(yfirst, ylast, indent, data)
  1775. X *     Fill lines {yfirst..ylast} with data, after skipping the initial
  1776. X *    'indent' positions. It is assumed that these positions do not contain
  1777. X *    anything dangerous (like standout cookies or null characters).
  1778. X *
  1779. X * trmscrollup(yfirst, ylast, by)
  1780. X *     Shift lines {yfirst..ylast} up by lines (down |by| if by < 0).
  1781. X *
  1782. X * trmsync(y, x)
  1783. X *     Call to output data to the terminal and set cursor position.
  1784. X *
  1785. X * trmbell()
  1786. X *    Send a (possibly visible) bell, immediately (flushing stdout).
  1787. X *
  1788. X * trmend()
  1789. X *     Obligatory termination call (resets tty modes etc.).
  1790. X *
  1791. X * You may call these as one or more cycles of:
  1792. X *     + trmstart
  1793. X *     +    zero or more times any of the other routines
  1794. X *     + trmend
  1795. X * Trmend may be called even in the middle of trmstart; this is necessary
  1796. X * to make it possible to write an interrupt handler that resets the tty
  1797. X * state before exiting the program.
  1798. X *
  1799. X * ADDITIONAL SPECIFICATIONS (ROUTINES FOR CHARACTER INPUT)
  1800. X *
  1801. X * trminput()
  1802. X *    Return the next input character (with its parity bit cleared
  1803. X *    if any).  This value is a nonnegative int.  Returns -1 if the
  1804. X *    input can't be read any more.
  1805. X *
  1806. X * trmavail()
  1807. X *    Return 1 if there is an input character immediately available,
  1808. X *    0 if not.  Return -1 if not implementable.
  1809. X *
  1810. X * trminterrupt()
  1811. X *    Return 1 if an interrupt has occurred since the last call to
  1812. X *    trminput or trmavail, 0 else.  [Currently not implemented.]
  1813. X *
  1814. X * trmsuspend()
  1815. X *    When called in the proper environment (4BSD with job control
  1816. X *    enabled), suspends the editor, temporarily popping back to
  1817. X *    the calling shell.  The caller should have called trmend()
  1818. X *    first, and must call trmstart again afterwards.
  1819. X *    BUG: there is a timing window where keyboard-generated
  1820. X *    signals (such as interrupt) can reach the program.
  1821. X */
  1822. @//E*O*F vtrm.c//
  1823. if test 38157 -ne "`wc -c <'vtrm.c'`"; then
  1824.     echo shar: error transmitting "'vtrm.c'" '(should have been 38157 characters)'
  1825. fi
  1826. fi # end of overwriting check
  1827. echo shar: "End of archive 2 (of 2)."
  1828. cp /dev/null ark2isdone
  1829. DONE=true
  1830. for I in 1 2; do
  1831.     if test -! f ark${I}isdone; then
  1832.         echo "You still need to run archive ${I}."
  1833.         DONE=false
  1834.     fi
  1835. done
  1836. case $DONE in
  1837.     true)
  1838.         echo "You have run all 2 archives."
  1839.         echo 'Now see the README'
  1840.         ;;
  1841. esac
  1842. ##  End of shell archive.
  1843. exit 0
  1844.